package com.arpa.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.arpa.core.web.Result;
import com.arpa.ntocc.common.common.cache.PartyCache;
import com.arpa.ntocc.common.common.util.CommonUtil;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.wms.cache.LocationCache;
import com.arpa.wms.cache.UnitCache;
import com.arpa.wms.cache.WarehouseCache;
import com.arpa.wms.cache.WarehouseSpaceCache;
import com.arpa.wms.domain.consts.CommonConst;
import com.arpa.wms.domain.dto.InventoryRecordDTO;
import com.arpa.wms.domain.entity.Inventory;
import com.arpa.wms.domain.entity.InventoryRecord;
import com.arpa.wms.domain.enums.InventoryRecordTypeEnum;
import com.arpa.wms.domain.vo.InventoryRecordVO;
import com.arpa.wms.mapper.InventoryRecordMapper;
import com.arpa.wms.service.IInventoryRecordService;
import com.arpa.wms.service.IInventoryService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @author: Allen chen
 * @Date 2020/8/25
 * @Description: 库存记录Service
 */
@Service
public class InventoryRecordServiceImpl extends ServiceImpl<InventoryRecordMapper, InventoryRecord> implements IInventoryRecordService {

    private final PartyCache partyCache;

    private final WarehouseSpaceCache warehouseSpaceCache;

    private final WarehouseCache warehouseCache;

    private final UnitCache unitCache;

    private final LocationCache locationCache;

    @Autowired
    @Lazy
    private IInventoryService iInventoryService;

    public InventoryRecordServiceImpl(PartyCache partyCache, WarehouseSpaceCache warehouseSpaceCache, WarehouseCache warehouseCache, UnitCache unitCache, LocationCache locationCache) {
        this.partyCache = partyCache;
        this.warehouseSpaceCache = warehouseSpaceCache;
        this.warehouseCache = warehouseCache;
        this.unitCache = unitCache;
        this.locationCache = locationCache;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public boolean save(InventoryRecord entity) {
        if (StrUtil.isEmpty(entity.getCreatedBy())) {
            entity.setCreatedBy(UserUtil.getCode());
            entity.setCreatedName(partyCache.translate(UserUtil.getCode()));
        }
        if (StrUtil.isEmpty(entity.getModifiedBy())) {
            entity.setModifiedBy(entity.getCreatedBy());
            entity.setModifiedName(entity.getCreatedName());
        }
        boolean flag = super.save(entity);

        return flag;
    }

    @Override
    public List<InventoryRecordVO> queryList(InventoryRecordDTO inventoryRecordDTO) {
        //排序字段名需要驼峰转数据库下划线类型字段名
        if (StringUtils.isNotEmpty(inventoryRecordDTO.getSortField())) {
            inventoryRecordDTO.setSortField(CommonUtil.camel2Underline(inventoryRecordDTO.getSortField()));
        }

        List<InventoryRecordVO> inventoryRecordVoS = baseMapper.queryList(inventoryRecordDTO);
        inventoryRecordVoS.forEach(info ->{
            info.setWarehouseSpaceName(warehouseSpaceCache.translate(info.getWarehouseSpaceCode()));
            info.setWarehouseName(warehouseCache.translate(info.getWarehouseCode()));
            info.setLocationName(locationCache.translate(info.getLocation()));
            info.setTypeName(InventoryRecordTypeEnum.translate(info.getType()));
        });

        return inventoryRecordVoS;
    }

    @Override
    public InventoryRecordVO queryListSum(InventoryRecordDTO inventoryRecordDTO) {
        return baseMapper.queryListSum(inventoryRecordDTO);
    }

    /**
     * 插入库存记录信息
     *
     * @param inventory 库存信息
     * @param sourceNo  来源单号，如入库单号、移位单号、差异单号
     * @param num       操作数量，正负表示增加或减少
     * @param type      操作类型，如收货、入库、拣货、出库、移位, 在InventoryRecordTypeEnum对象中
     * @return
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Result insertRecord(Inventory inventory, String sourceNo, BigDecimal num, String type) {
        InventoryRecord inventoryRecord = makeRecord(inventory, sourceNo, num, type);

        this.save(inventoryRecord);
        return Result.ok();
    }

    /**
     * 异步插入库存记录信息
     *
     * @param inventory 库存信息
     * @param sourceNo  来源单号，如入库单号、移位单号、差异单号
     * @param num       操作数量，正负表示增加或减少
     * @param type      操作类型，如收货、入库、拣货、出库、移位, 在InventoryRecordTypeEnum对象中
     * @return
     */
    @Override
    @Async
    public void asynInsertRecord(Inventory inventory, String sourceNo, BigDecimal num, String type) {
        this.insertRecord(inventory,sourceNo,num,type);
    }

    /**
     * 生成库存日志记录
     * @param inv
     * @param sourceNo
     * @param num
     * @param type
     * @return
     */
    @Override
    public InventoryRecord makeRecord(Inventory inv, String sourceNo, BigDecimal num, String type) {
        InventoryRecord inventoryRecord = new InventoryRecord();
        BeanUtil.copyProperties(inv, inventoryRecord);
        inventoryRecord.setCode(IdUtil.simpleUUID());
        inventoryRecord.setGroupCode(inv.getGroupCode());
        inventoryRecord.setInventoryCode(inv.getCode());
        inventoryRecord.setSourceCode(sourceNo);
        inventoryRecord.setNum(num);
        inventoryRecord.setType(type);

        return inventoryRecord;
    }

    /**
     * 插入库存记录信息， 与同名的insertRecord作用一样，用于没有库存对象，只有库存编码的情况
     * @param invCode 库存编码
     * @param sourceNo  来源单号，如入库单号、移位单号、差异单号
     * @param num   操作数量，正负表示增加或减少
     * @param type  操作类型，如收货、入库、拣货、出库、移位, 在InventoryRecordTypeEnum对象中
     * @return
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Result insertRecord(String invCode, String sourceNo, BigDecimal num, String type) {
        Inventory inventory = iInventoryService.getOne(new QueryWrapper<Inventory>().lambda().eq(Inventory::getCode, invCode));
        insertRecord(inventory, sourceNo, num, type);
        return Result.ok();
    }

    /**
     * 执行sql
     *
     * @param sql
     */
    @Override
    public void execSql(String sql) {
        this.baseMapper.execSql(sql);
    }


}
